package ws.jonas.hoarder;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import ws.jonas.common.config.Config;
import ws.jonas.common.log.Logger;
import ws.jonas.common.model.Product;
import ws.jonas.common.model.ProductQuantity;
import ws.jonas.common.model.Store;
import ws.jonas.common.web.WebQuerier;
import ws.jonas.hoarder.db.MssqlDb;
import ws.jonas.hoarder.db.MysqlDb;
import ws.jonas.hoarder.db.SqlDb;

public class Hoarder {
	private static final Logger log = Logger.getInstance(Hoarder.class);
	private SqlDb db;

	public static void main(String[] args) {
		if (args.length > 0) {
			log.info("Ignoring command line parameters (no options available)");
		}
		try {
			new Hoarder().run();
		} catch (Exception e) {
			log.severe("Unhandled exception, aborting...");
			log.severe(e);
			//Quit
		}
	}

	public void run() {
		try {
			Config.updateConfig();

			if (Config.get(Config.DB_VENDOR_KEY).equalsIgnoreCase("mysql")) {
				db = new MysqlDb();
			} else if (Config.get(Config.DB_VENDOR_KEY).equalsIgnoreCase("mssql")) {
				db = new MssqlDb();
			} else {
				log.severe("Invalid database vendor: " + Config.get(Config.DB_VENDOR_KEY));
				return;
			}

			scrape();
		} catch (SQLException e) {

		} catch (IOException e) {

		} finally {
			log.sendMails();
		}
	}

	private void scrape() {
		ArrayList<String> prodnrs = readProdnrsFromFile();
		for (int i = 0; i < prodnrs.size(); ++i) {
			String prodnr = prodnrs.get(i);
			List<ProductQuantity> products = null;
			try {
				products = WebQuerier.query(prodnr);
			} catch (NumberFormatException e) {
				log.warning("Failed to parse prodnr: " + prodnr + ", skipping");
				continue;
			}

			if (products == null) {
				continue;
			}

			for (ProductQuantity productQuantity : products) {
				Product product = productQuantity.getProduct();

				try {
					db.addProductIfNotExists(product.getProdnr(), product.getName(), product.getVolume());
				} catch (SQLException e) {
					log.severe("Could not add product: " + product);
					log.severe(e);
				}

				for (Map.Entry<Store, Integer> entry : productQuantity) {
					Store store = entry.getKey();
					int quantity = entry.getValue();

					try {
						db.addStoreIfNotExists(store);
					} catch (SQLException e) {
						log.severe("Could not add store: " + store);
						log.severe(e);
					}

					try {
						db.addStock(product.getProdnr(), product.getName(), product.getVolume(), quantity, store);
					} catch (SQLException e) {
						log.severe("Could not add stock: product=" + product + ", store=" + store);
						log.severe(e);
					}
				}
			}

			if (i != prodnrs.size() - 1) { //Dont bother sleeping if last iteration
				Random rnd = new Random();
				try {
					long sleepTime = 0;
					try {
						int queryMs = Integer.parseInt(Config.get(Config.QUERY_MS_KEY));
						int queryDeviationMs = Integer.parseInt(Config.get(Config.QUERY_DEVIATION_MS_KEY));
						if (queryMs != 0) {
							if (queryDeviationMs != 0) {
								sleepTime = queryMs - queryDeviationMs + rnd.nextInt(queryDeviationMs) * 2;
							} else {
								sleepTime = queryMs;
							}
						}
					} catch (NumberFormatException e) {
						log.warning("Failed to parse query sleep times, taking default value");
						sleepTime = Integer.parseInt(Config.getDefault(Config.QUERY_MS_KEY)) - Integer.parseInt(Config.getDefault(Config.QUERY_DEVIATION_MS_KEY)) + rnd.nextInt(Integer.parseInt(Config.getDefault(Config.QUERY_DEVIATION_MS_KEY)) * 2);
					}
					if (sleepTime > 0) {
						log.fine("Sleeping for " + (double)sleepTime / 1000 + " seconds");
						Thread.sleep(sleepTime);
					}
				} catch (InterruptedException e) {
					log.warning(e);
					Thread.currentThread().interrupt();
				}
			}
		}
	}

	private ArrayList<String> readProdnrsFromFile() {
		BufferedReader fileIn = null;
		ArrayList<String> ret = new ArrayList<String>();
		try {
			fileIn = new BufferedReader(new FileReader(Config.get(Config.PRODNR_FILE_KEY)));
			String line = null;
			while ((line = fileIn.readLine()) != null) {
				if (line.startsWith("#") || line.equals("")) {
					continue;
				}
				if (line.indexOf("#") != -1) {
					line = line.substring(0, line.indexOf("#")).trim();
				}
				log.fine("Adding prodnr " + line + " to query list");
				ret.add(line);
			}
		} catch (IOException e) {
			log.severe("Could not find/read prodnr file (" + new File(Config.get(Config.PRODNR_FILE_KEY)).getAbsolutePath() + "): " + e);
		} finally {
			try {
				if (fileIn != null) {
					fileIn.close();
				}
			} catch (IOException e) {
				log.warning(e);
			}
		}
		return ret;
	}
}
